/**************************
SEG - Smooth Expander Gate
Copyright (C) 2015 Stige T.
**************************/

desc:SEG - Smooth Expander Gate [Build 151011]

slider1:0<0,10,0.1>Attack
slider2:20<20,1000,1>Release
slider3:-45<-90,0,1>Threshold
slider4:1<0.5,10,0.1>Ratio [Expander <> Gate]
slider5:20<20,2000,1>SC Lo Cut
slider6:20000<200,20000,1>SC Hi Cut
slider7:0<0,2,1{Output,SideChain,Detector}>Monitor
slider8:0<0,1,1{Off (0spl),On (64spl)}>Pre-Gate

@init

t20 = exp(-1/(srate*0.02));
t40 = exp(-1/(srate*0.04));

function delay64spl(input) (
  this.x0 = input;
  this.x65=this.x64; this.x64=this.x63; this.x63=this.x62; this.x62=this.x61; this.x61=this.x60; this.x60=this.x59; this.x59=this.x58;
  this.x58=this.x57; this.x57=this.x56; this.x56=this.x55; this.x55=this.x54; this.x54=this.x53; this.x53=this.x52; this.x52=this.x51;
  this.x51=this.x50; this.x50=this.x49; this.x49=this.x48; this.x48=this.x47; this.x47=this.x46; this.x46=this.x45; this.x45=this.x44;  
  this.x44=this.x43; this.x43=this.x42; this.x42=this.x41; this.x41=this.x40; this.x40=this.x39; this.x39=this.x38; this.x38=this.x37;
  this.x37=this.x36; this.x36=this.x35; this.x35=this.x34; this.x34=this.x33; this.x33=this.x32; this.x32=this.x31; this.x31=this.x30;
  this.x30=this.x29; this.x29=this.x28; this.x28=this.x27; this.x27=this.x26; this.x26=this.x25; this.x25=this.x24; this.x24=this.x23;
  this.x23=this.x22; this.x22=this.x21; this.x21=this.x20; this.x20=this.x19; this.x19=this.x18; this.x18=this.x17; this.x17=this.x16;
  this.x16=this.x15; this.x15=this.x14; this.x14=this.x13; this.x13=this.x12; this.x12=this.x11; this.x11=this.x10; this.x10=this.x9;
  this.x9=this.x8; this.x8=this.x7; this.x7=this.x6; this.x6=this.x5; this.x5=this.x4; this.x4=this.x3; this.x3=this.x2; this.x2=this.x1; this.x1=this.x0;
  this.x65;
);

function HFLF_init(freq)
instance(n0,weight)
(
  n0 = 0;
  weight = 1-exp(-2*$pi*freq/srate);
);

function HFcut(input)
instance(out,n0,weight)
(  
  out = (n0+=((input-n0)*weight));
);

function LFcut(input)
instance(out,n0,weight)
(
  out = input - (n0+=((input-n0)*weight));
);

function follower(input,att,rel)
instance (env,tmp) (
  tmp = input >= tmp ? input : input + t40 * (tmp-input);
  (tmp > env) ? (
      env = att * (env - tmp) + tmp;
  ) : (
      env = rel * (env - tmp) + tmp;
  );
);

function expander_gate(input,threshold,attack,release,ratio,locut,hicut,mon)
instance(env,e1,e2,e3,output,key,f1,f2,mon)
(
  key = input;
  hicut < 20000 ? (
    key = f1.HFcut(input);
  );
  locut > 20 ? (
    key = f2.LFcut(key);
  );
  env = min(abs(key),threshold);
  env = env / threshold;
  env = env^ratio;
  env = e1.follower(env,attack,release);
  
  lat ? (  
    input = this.delay64spl(input);
  );
  
  !mon ? (
    output = input * env;
  );
  mon == 1 ? (
    output = key;
  );
  mon == 2 ? (
    output = (input * env) - input;
  );
  output;
);

@slider

attack = exp(-1/(srate*slider1/1000));
release = exp(-1/(srate*slider2/1000));
threshold = 10^(slider3/20);
locut = slider5;
hicut = slider6;
mon = slider7;
ratio = slider4;
lat = slider8;

L.f1.HFLF_init(hicut);
L.f2.HFLF_init(locut);
R.f1.HFLF_init(hicut);
R.f2.HFLF_init(locut);

lat ? (
  pdc_delay = 64;
  pdc_bot_ch = 0; pdc_top_ch = 2;
);

@sample

spl0 != spl1 ? (
  spl0 = L.expander_gate(spl0,threshold,attack,release,ratio,locut,hicut,mon);
  spl1 = R.expander_gate(spl1,threshold,attack,release,ratio,locut,hicut,mon);
  renv = max(L.env,R.env);
) : (
  spl0 = spl1 = L.expander_gate(spl0,threshold,attack,release,ratio,locut,hicut,mon);
  renv = L.env;
);

@gfx

gfx_setfont(1,"Arial",14);

x_pos = floor(gfx_w/2)-100;
y_pos = 10;
gfx_r = 1; gfx_g = 1; gfx_b = 1; gfx_a = 1;
gfx_x = x_pos; gfx_y = y_pos;
gfx_rectto(200+x_pos,20+y_pos);
gfx_x = 199+x_pos; gfx_y = 20+y_pos;
gfx_lineto(199+x_pos,30+y_pos,0);
gfx_drawchar($'O');
gfx_x = 112+x_pos; gfx_y = 20+y_pos;
gfx_lineto(112+x_pos,30+y_pos,0);
gfx_drawnumber(10,0);
gfx_x = 64+x_pos; gfx_y = 20+y_pos;
gfx_lineto(64+x_pos,30+y_pos,0);
gfx_drawnumber(20,0);
gfx_x = 20+x_pos; gfx_y = 20+y_pos;
gfx_lineto(20+x_pos,30+y_pos,0);
gfx_drawnumber(40,0);
gfx_x = x_pos; gfx_y = 20+y_pos;
gfx_lineto(x_pos,30+y_pos,0);
gfx_drawchar($'C');

gfx_r = 0; gfx_g = 0.9; gfx_b = 0; gfx_a = 1;
gfx_x = 199+x_pos;
gfx_y = y_pos+1;
redux = floor(max(sqrt( renv )*200,1));
gfx_rectto(redux+x_pos,19+y_pos);

gfx_r = 1; gfx_g = 1; gfx_b = 1; gfx_a = 1;
gfx_x = x_pos-20; gfx_y = y_pos;
gfx_rectto(x_pos-10,20+y_pos);
gfx_x = 210+x_pos; gfx_y = y_pos;
gfx_rectto(220+x_pos,20+y_pos);

redux == 1 ? (
  col1 = 1;
);
redux >= 199 ? (
  col2 = 1;
);

gfx_r = 1 * col1; gfx_g = 0; gfx_b = 0;
gfx_x = x_pos-19; gfx_y = y_pos+1;
gfx_rectto(x_pos-11,19+y_pos);

gfx_r = 1 * col2; gfx_g = 0; gfx_b = 0;
gfx_x = 211+x_pos; gfx_y = y_pos+1;
gfx_rectto(219+x_pos,19+y_pos);

col1 = max(col1-0.05,0);
col2 = max(col2-0.05,0);
